﻿#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <complex>
#include <cmath>
#include <algorithm>
#include <opencv2/opencv.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/features2d/features2d.hpp>
#include <opencv2/calib3d/calib3d.hpp>
#include <opencv2/nonfree/nonfree.hpp>


/****************************************************************************/
using namespace std;
using namespace cv;
/****************************************************************************/
#define NUM_MARKER 18
/****************************************************************************/
Mat img1;
Mat img2;
vector<Point2f> markers1;
vector<Point2f> markers2;
vector<KeyPoint> keypoints1;
vector<KeyPoint> keypoints2;
FileStorage fs;
ostringstream oss;
Mat img_matches;
/****************************************************************************/
void onMouseImage1(int event,		//Event of mouse
				   int x,			//x position
				   int y,			//y position
				   int flags, 
				   void*)
{
	Point pointClicked;
	switch(event) 
	{
	case CV_EVENT_LBUTTONDBLCLK:
		pointClicked = Point(x, y);		//Get current point
		//cout << x << "\t" << y << endl;
		
 		if(markers1.size() < NUM_MARKER)
 		{
			cout << pointClicked << endl;
			cout << (unsigned int)img1.at<uchar>(pointClicked) << endl;
 			markers1.push_back(pointClicked);
 		}
		else
		{
			cout << "Full.." << endl;
			cout << "Reset." << endl;

			markers1.clear();
		}
		break; 
	default:
		break;
	}
}
/****************************************************************************/
void onMouseImage2(int event,		//Event of mouse
	int x,			//x position
	int y,			//y position
	int flags, 
	void*)
{
	Point pointClicked;
	switch(event) 
	{
	case CV_EVENT_LBUTTONDBLCLK:
		pointClicked = Point(x, y);		//Get current point
		//cout << x << "\t" << y << endl;

		if(markers2.size() < NUM_MARKER)
		{
			cout << pointClicked << endl;
			cout << (unsigned int)img2.at<uchar>(pointClicked) << endl;
			markers2.push_back(pointClicked);
		}
		else
		{
			cout << "Full.." << endl;
			cout << "Reset." << endl;
			markers2.clear();
		}
		break; 
	default:
		break;
	}
}
/****************************************************************************/
void onMouse(int event,		//Event of mouse
	int x,			//x position
	int y,			//y position
	int flags, 
	void*)
{
	switch (event)
	{
	case CV_EVENT_LBUTTONUP:
// 		cout << markers1.size() << endl;
// 		cout << markers2.size() << endl;
		if(markers1.size()== NUM_MARKER && markers2.size()==NUM_MARKER)
		{

			//vector<KeyPoint> keypoints1;
			KeyPoint().convert(markers1, keypoints1);
			//vector<KeyPoint> keypoints2;
			KeyPoint().convert(markers2, keypoints2);


			//////////////////////////////////////////////////////////////////////////
			//Manually Matching Marker
			vector<DMatch> matches;


			vector<pair<int, int>> pairMatch;
			for(int i=0; i<NUM_MARKER; i++)
			{
				pairMatch.push_back(pair<int, int>(i, i));
			}
			for(int i=0; i<NUM_MARKER; i++)
			{
				matches.push_back(DMatch(pairMatch[i].first, pairMatch[i].second, 
					std::numeric_limits<float>::max()));
			}
			//////////////////////////////////////////////////////////////////////////
			drawMatches(img1, keypoints1, 
				img2, keypoints2, 
				matches, img_matches, 
				Scalar::all(-1), Scalar::all(-1),
				vector<char>(), 
				DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS );
			imshow("Matching Points", img_matches);
			imwrite("Matching.jpg", img_matches);
		}
		else if(keypoints1.size()== NUM_MARKER && keypoints2.size()==NUM_MARKER)
		{
			vector<DMatch> matches;


			vector<pair<int, int>> pairMatch;
			for(int i=0; i<NUM_MARKER; i++)
			{
				pairMatch.push_back(pair<int, int>(i, i));
			}
			for(int i=0; i<NUM_MARKER; i++)
			{
				matches.push_back(DMatch(pairMatch[i].first, pairMatch[i].second, 
					std::numeric_limits<float>::max()));
			}
			drawMatches(img1, keypoints1, 
				img2, keypoints2, 
				matches, img_matches, 
				Scalar::all(-1), Scalar::all(-1),
				vector<char>(), 
				DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS );
			imshow("Matching Points", img_matches);
			imwrite("Matching.jpg", img_matches);
		}
		else
		{
			cout << "Not enough" <<endl;
		}
		break; 
	case CV_EVENT_RBUTTONUP:
		//Save current Key point
		fs = FileStorage("Data.xml", FileStorage::WRITE);
// 		fs << "keypoints1" << keypoints1;
// 		fs << "keypoints2" << keypoints2;
		
		write(fs, "keypoints1", keypoints1);
		write(fs, "keypoints2", keypoints2);
		fs.release();
		break;
	case CV_EVENT_MBUTTONDOWN:
		//LOAD current Key point
		fs = FileStorage("Data.xml", FileStorage::READ);
		cout<<"Read" <<endl;
		read(fs["keypoints1"], keypoints1);
		read(fs["keypoints2"], keypoints2);
		cout<< keypoints1.size() << endl;
		cout<< keypoints2.size() << endl;
		fs.release();
		break;
	default:
		break;
	}

}
/****************************************************************************/
int main() 
{
	img1 = imread("spiderman1.jpg", CV_LOAD_IMAGE_GRAYSCALE);
	img2 = imread("spiderman2.jpg", CV_LOAD_IMAGE_GRAYSCALE);
	if(img1.empty() || img2.empty())
	{
		return -1;
	}
	//////////////////////////////////////////////////////////////////////////
	//Display images
	imshow("Image 1", img1);
	imshow("Image 2", img2);
	namedWindow("Matching Points");

	//////////////////////////////////////////////////////////////////////////
	//Manually selected marker on image 1

		setMouseCallback("Image 1", 
			onMouseImage1, 
			0);
		setMouseCallback("Image 2", 
			onMouseImage2, 
			0);
		setMouseCallback("Matching Points", 
			onMouse, 
			0);

	//system("Pause");
// 	cout << "Here 1" <<endl;
// 	cout << markers1.size() << endl;
// 	cout << markers2.size() << endl;
// 	if(markers1.size()== NUM_MARKER && markers2.size()==NUM_MARKER)
// 	{
// 		Mat img_matches;
// 		vector<KeyPoint> keypoints1;
// 		KeyPoint().convert(markers1, keypoints1);
// 		vector<KeyPoint> keypoints2;
// 		KeyPoint().convert(markers2, keypoints2);
// 
// 		// Draw the key points
// 		Mat imageKP;
// 		drawKeypoints(img1, keypoints1, 
// 		 				imageKP, Scalar(255,255,255), 
// 		 				DrawMatchesFlags::DRAW_RICH_KEYPOINTS);
// 		imshow("Left  Fast Features", imageKP);
// 		drawKeypoints(img2, keypoints2, 
// 		 				imageKP, Scalar(255,255,255), 
// 		 				DrawMatchesFlags::DRAW_RICH_KEYPOINTS);
// 		imshow("Right Fast Features", imageKP);
		//drawMatches(img1, )
// 		drawMatches(img1, keypoints1, 
// 					img2, keypoints2, 
// 					good_matches, img_matches, 
// 					Scalar::all(-1), Scalar::all(-1),
// 					vector<char>(), 
// 					DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS );
		//imshow("Matches Point", img_matches);
//	}
	

// 
// 		//////////////////////////////////////////////////////////////////////////
// 		//Vector of Key points
// 		vector<KeyPoint> keypoints1;
// 		vector<KeyPoint> keypoints2;
// 	
// 		//////////////////////////////////////////////////////////////////////////
// 		//Construct SURF Feature Detector
// 		Ptr<FeatureDetector> surfDetector = new SURF(600.0);
// 
// 		surfDetector->detect(img1,keypoints1);
// 		surfDetector->detect(img2,keypoints2);
// 
// 		cout << "Number of SURF points (1): " << keypoints1.size() << endl;
// 		cout << "Number of SURF points (2): " << keypoints2.size() << endl;
// 		//////////////////////////////////////////////////////////////////////////
// 		// Draw the key points
// 		Mat imageKP;
// 		drawKeypoints(img1, keypoints1, 
// 					  imageKP, Scalar(255,255,255), 
// 					  DrawMatchesFlags::DRAW_RICH_KEYPOINTS);
// 		imshow("Left  Fast Features", imageKP);
// 		drawKeypoints(img2, keypoints2, 
// 					  imageKP, Scalar(255,255,255), 
// 					  DrawMatchesFlags::DRAW_RICH_KEYPOINTS);
// 		imshow("Right Fast Features", imageKP);
// 
// 		//////////////////////////////////////////////////////////////////////////
//  		Mat descriptors1, descriptors2;
//  		Ptr<DescriptorExtractor> surfExtractor = new SURF(600.0);
// 		surfExtractor->compute(img1, keypoints1, descriptors1);
// 		surfExtractor->compute(img2, keypoints2, descriptors2);
// 
// 		cout << "Descriptor matrix size: " << descriptors1.rows 
// 			 << " by " << descriptors1.cols << endl;
// 		//////////////////////////////////////////////////////////////////////////
// 		// Construction of the matcher 
// 	//  	Ptr<DescriptorMatcher> descriptorMatcher = new DescriptorMatcher()
// 	//  	vector<DMatch> matches;
// 	//  
// 	//  	descriptorMatcher->match(descriptors1, descriptors2, matches);
// 	//  	cout << "Number of matched points: " << matches.size() << endl;
// 	
// 		FlannBasedMatcher matcher;
// 		vector<DMatch> matches;
// 		matcher.match(descriptors1, descriptors2, matches);
// 		cout << "Number of matched points: " << matches.size() << endl;
// 		//////////////////////////////////////////////////////////////////////////
// 		double max_dist = 0; double min_dist = 100;
// 
// 		//Quick calculation of max and min distances between keypoints
// 		for( int i = 0; i < descriptors1.rows; i++ )
// 		{ 
// 			double dist = matches[i].distance;
// 			if(dist<min_dist) 
// 				min_dist = dist;
// 			if(dist>max_dist) 
// 				max_dist = dist;
// 		}
// 
// 		cout << "-- Max dist : "<< max_dist <<endl;
// 		cout << "-- Min dist : "<< min_dist <<endl;
// 
// 		//Draw only "good" matches (i.e. whose distance is less than 3*min_dist )
// 		std::vector< DMatch > good_matches;
// 
// 		for(int i=0; i<descriptors1.rows; i++)
// 		{ 
// 			if(matches[i].distance < 3*min_dist)
// 				good_matches.push_back( matches[i]); 
// 		}
// 
// 		Mat img_matches;
// 		drawMatches(img1, keypoints1, 
// 					img2, keypoints2, 
// 					good_matches, img_matches, 
// 					Scalar::all(-1), Scalar::all(-1),
// 					vector<char>(), 
// 					DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS );
// 		imshow("Matches Point", img_matches);
// 	//////////////////////////////////////////////////////////////////////////

	//////////////////////////////////////////////////////////////////////////
		waitKey();
	return 0;
}
/****************************************************************************/